home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Header: /private/postgres/src/rewrite/RCS/ViewDefine.c,v 2.9 1992/06/28 03:47:58 mao Exp $
- */
-
- #include "access/heapam.h"
- #include "catalog/syscache.h"
- #include "utils/log.h"
- #include "nodes/relation.h"
- #include "nodes/relation.a.h"
- #include "nodes/primnodes.h"
- #include "nodes/primnodes.a.h"
- #include "parser/parsetree.h"
-
- /* #include "catalog_utils.h" */
-
- #include "./RewriteManip.h"
-
- extern Name tname();
- void makeRetrieveViewRuleName();
-
- Name
- attname ( relname , attnum )
- Name relname;
- int attnum;
- {
- Relation relptr;
- HeapTuple atp;
- ObjectId reloid;
- Name varname;
-
- relptr = amopenr (relname );
- reloid = RelationGetRelationId ( relptr );
-
- atp = SearchSysCacheTuple ( ATTNUM, reloid, attnum , NULL, NULL );
- if (!HeapTupleIsValid(atp)) {
- elog(WARN, "getattnvals: no attribute tuple %d %d",
- reloid, attnum);
- return(0);
- }
- varname = (Name)&( ((AttributeTupleForm) GETSTRUCT(atp))->attname );
-
- return ( varname );
- }
-
- /*---------------------------------------------------------------------
- * DefineVirtualRelation
- *
- * Create the "view" relation.
- * `DefineRelation' does all the work, we just provide the correct
- * arguments!
- *
- * If the relation already exists, then 'DefineRelation' will abort
- * the xact...
- *---------------------------------------------------------------------
- */
- DefineVirtualRelation (relname , tlist )
- Name relname;
- List tlist;
- {
- List attrList, t, element;
- List parameters;
- TLE entry;
- Resdom res;
- Name resname;
- ObjectId restype;
- Name restypename;
-
- /*
- * create a list with one entry per attribute of this relation.
- * Each entry is a two element list. The first element is the
- * name of the attribute (a string) and the second the name of the type
- * (NOTE: a string, not a type id!).
- */
- attrList = LispNil;
- if (!null(tlist)) {
- foreach (t, tlist ) {
- /*
- * find the names of the attribute & its type
- */
- entry = get_entry((TL)t);
- res = get_resdom(entry);
- resname = get_resname(res);
- restype = get_restype(res);
- restypename = tname(get_id_type(restype));
- element = lispCons(lispString(restypename), LispNil);
- element = lispCons(lispString(resname), element);
- attrList = nappend1(attrList, element);
- }
- } else {
- elog ( WARN, "attempted to define virtual relation with no attrs");
- }
-
- /*
- * now create the parametesr for keys/inheritance etc.
- * All of them are nil...
- */
- parameters = LispNil;
- parameters = lispCons(LispNil, parameters); /* keys */
- parameters = lispCons(LispNil, parameters); /* inheritance stuff */
- parameters = lispCons(LispNil, parameters); /* is indexable */
- parameters = lispCons(LispNil, parameters); /* archive type */
- parameters = lispCons(LispNil, parameters); /* heap store */
- parameters = lispCons(LispNil, parameters); /* archive store */
-
- /*
- * finally create the relation...
- */
- DefineRelation(relname, parameters, attrList);
- }
-
- #ifdef BOGUS
- -------------------------------------------------------------------------
- /* DefineVirtualRelation2
- * - takes a relation name and a targetlist
- * and generates a string "create relation ( ... )"
- * by taking the attributes and types from the tlist
- * and reconstructing the attr-list for create.
- * then calls "pg-eval" to evaluate the creation,
- */
- DefineVirtualRelation2 ( relname , tlist )
- Name relname;
- List tlist;
- {
- LispValue element;
- static char querybuf[1024];
- char *index = querybuf;
- int i;
-
- for ( i = 0 ; i < 1024 ; i++ ) {
- querybuf[i] = NULL;
- }
-
- sprintf(querybuf,"create %s(",relname );
- index += strlen(querybuf);
-
- if ( ! null ( tlist )) {
- foreach ( element, tlist ) {
- TLE entry = get_entry((TL)element);
- Resdom res = get_resdom(entry);
- Name resname = get_resname(res);
- ObjectId restype = get_restype(res);
- Name restypename = tname(get_id_type(restype));
-
- sprintf(index,"%s = %s,",resname,restypename);
- index += strlen(index);
- }
- *(index-1) = ')';
-
- } else
- elog ( WARN, "attempted to define virtual relation with no attrs");
- pg_eval(querybuf, (char *) NULL, (ObjectId *) NULL, 0);
- }
- -------------------------------------------------------------------------
- #endif BOGUS
-
- List
- my_find ( string, list )
- char *string;
- List list;
- {
- List i = NULL;
- List retval = NULL;
-
- for( i = list ; i != NULL; i = CDR(i) ) {
- if ( CAR(i) && IsA (CAR(i),LispList)) {
- retval = my_find ( string,CAR(i));
- if ( retval )
- break;
- } else if ( CAR(i) && IsA(CAR(i),LispStr) &&
- !strcmp(CString(CAR(i)),string) ) {
- retval = i;
- break;
- }
- }
- return(retval);
- }
-
- /*------------------------------------------------------------------
- * makeViewRetrieveRuleName
- *
- * Given a view name, create the name for the 'on retrieve to "view"'
- * rule.
- * This routine is called when defining/removing a view.
- *
- * NOTE: it quarantees that the name is at most 15 chars long
- *------------------------------------------------------------------
- */
- void
- makeRetrieveViewRuleName(rule_name, view_name)
- Name rule_name;
- Name view_name;
- {
- char buf[100];
-
- /*
- * make sure that no non-null characters follow the
- * '\0' at the end of the string...
- */
- bzero(buf, sizeof(buf));
- sprintf(buf, "_RET%s", view_name);
- buf[15] = '\0';
- bcopy(buf, &(rule_name->data[0]), 16);
- }
-
- /*-----------------------------------------------------------------------
- * FormViewRetrieveRule
- *
- * Form the "on retrieve to view" rule...
- * If the view definition is:
- * define mikeolson (...target_list...) where ...qual....
- * the rule will be:
- * define rule ret_mileolson is
- * on retrieve to mike_olson do instead
- * retrieve (...target_list...) where ...qual....
- *
- *-----------------------------------------------------------------------
- */
- #ifdef TUPLE_VIEW
- List
- FormViewRetrieveRule (view_name, view_parse)
- Name view_name;
- List view_parse;
- {
-
- NameData rname;
- List p, q, target, rt;
- List lispCopy();
-
- /*
- * Create a parse tree that corresponds to the suitable
- * tuple level rule...
- */
- p = LispNil;
- /*
- * this is an instance-level rule... (or tuple-level
- * for the traditionalists)
- */
- p = nappend1(p, lispAtom("instance"));
- /*
- * the second item in the list is the so called 'hint' : "(rule nil)"
- */
- p = nappend1(p, lispCons(lispAtom("rule"), lispCons(LispNil, LispNil)));
- /*
- * rule name now...
- */
- makeRetrieveViewRuleName(&rname, view_name);
- p = nappend1(p, lispString(&(rname.data[0])));
- /*
- * The next item is a big one...
- * First the 'event type' (retrieve), then the 'target' (the
- * view relation), then the 'rule qual' (no qualification in this
- * case), then the 'instead' information (yes, this is an instead
- * rule!) and finally the 'rule actions', whish is nothing else from
- * a list containing the view parse!
- */
- q = LispNil;
- q = nappend1(q, lispAtom("retrieve"));
- target = lispCons(lispString(view_name), LispNil);
- q = nappend1(q, target);
- q = nappend1(q, LispNil);
- q = nappend1(q, lispInteger(1));
- q = nappend1(q, lispCons(lispCopy(view_parse), LispNil));
- p = nappend1(p, q);
- /*
- * now our final item, the range table...
- */
- rt = lispCopy(root_rangetable(parse_root(view_parse)));
- p = nappend1(p, rt);
-
- return(p);
-
- }
- #endif TUPLE_VIEW
- List
- FormViewRetrieveRule (view_name, view_parse)
- Name view_name;
- List view_parse;
- {
-
- NameData rname;
- List p, q, target, rt;
- List lispCopy();
-
- /*
- * Create a lisp tree that corresponds to the suitable
- * rewrite rule args for DefineQueryRewrite();
- */
- p = LispNil;
- makeRetrieveViewRuleName(&rname, view_name);
- p = nappend1(p, lispString(&(rname.data[0]))); /* rulename */
- p = nappend1(p,lispAtom("retrieve")); /* event_type */
- p = nappend1(p,lispCons(lispString(view_name),LispNil)); /* event_obj */
- p = nappend1(p,lispCons(LispNil,LispNil)); /* event_qual */
- p = nappend1(p,lispInteger(1)); /* is_instead */
- q = nappend1(LispNil, view_parse);
- p = nappend1(p,q); /* (action) */
- return p;
- }
- static void
- DefineViewRules (view_name, view_parse)
- Name view_name;
- List view_parse;
- {
- List retrieve_rule = NULL;
- char ruleText[1000];
- #ifdef NOTYET
- List replace_rule = NULL;
- List append_rule = NULL;
- List delete_rule = NULL;
- #endif
-
- retrieve_rule =
- FormViewRetrieveRule (view_name, view_parse);
-
- #ifdef NOTYET
-
- replace_rule =
- FormViewReplaceRule ( view_name, view_tlist, view_rt, view_qual);
- append_rule =
- FormViewAppendRule ( view_name, view_tlist, view_rt, view_qual);
- delete_rule =
- FormViewDeleteRule ( view_name, view_tlist, view_rt, view_qual);
-
- #endif
-
- sprintf(ruleText, "retrieve rule for view %s", view_name);
- DefineQueryRewrite(retrieve_rule);
- #ifdef TUPLE_VIEW
- prs2DefineTupleRule(retrieve_rule, ruleText);
- #endif TUPLE_VIEW
- #ifdef NOTYET
- DefineQueryRewrite ( replace_rule );
- DefineQueryRewrite ( append_rule );
- DefineQueryRewrite ( delete_rule );
- #endif
-
- }
-
- /*---------------------------------------------------------------
- * UpdateRangeTableOfViewParse
- *
- * Update the range table of the given parsetree.
- * This update consists of adding two new entries IN THE BEGINNING
- * of the range table (otherwise the rule system will die a slow,
- * horrible and painful death, and we do not want that now, do we?)
- * one for the CURRENT relation and one for the NEW one (both of
- * them refer in fact to the "view" relation).
- *
- * Of course we must also increase the 'varnos' of all the Var nodes
- * by 2...
- *
- * NOTE: these are destructive changes. It would be difficult to
- * make a complete copy of the parse tree and make the changes
- * in the copy. 'lispCopy' is not enough because it onyl does a high
- * level copy (i.e. the Var nodes remain the same, so the varno offset
- * will update both parsetrees) and I am not confident that
- * 'copyfuncs.c' are bug free...
- *---------------------------------------------------------------
- */
- void
- UpdateRangeTableOfViewParse(view_name, view_parse)
- Name view_name;
- List view_parse;
- {
- List old_rt;
- List new_rt;
- List root;
- List rt_entry1, rt_entry2;
- List MakeRangeTableEntry();
-
- /*
- * first offset all var nodes by 2
- */
- OffsetVarNodes(view_parse, 2);
-
- /*
- * find the old range table...
- */
- root = parse_root(view_parse);
- old_rt = root_rangetable(root);
-
- /*
- * create the 2 new range table entries and form the new
- * range table...
- * CURRENT first, then NEW....
- */
- rt_entry1 = MakeRangeTableEntry(view_name, LispNil, "*CURRENT*");
- rt_entry2 = MakeRangeTableEntry(view_name, LispNil, "*NEW*");
- new_rt = lispCons(rt_entry2, old_rt);
- new_rt = lispCons(rt_entry1, new_rt);
-
- /*
- * Now the tricky part....
- * Update the range table in place... Be careful here, or
- * hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
- */
- root_rangetable(root) = new_rt;
- }
-
- /*-------------------------------------------------------------------
- * DefineView
- *
- * - takes a "viewname", "parsetree" pair and then
- * 1) construct the "virtual" relation
- * 2) commit the command but NOT the transaction,
- * so that the relation exists
- * before the rules are defined.
- * 2) define the "n" rules specified in the PRS2 paper
- * over the "virtual" relation
- *-------------------------------------------------------------------
- */
-
- void
- DefineView(view_name, view_parse)
- Name view_name;
- List view_parse;
- {
-
- List view_tlist;
-
- view_tlist = parse_targetlist( view_parse );
-
- /*
- * Create the "view" relation
- * NOTE: if it already exists, the xaxt will be aborted.
- */
- DefineVirtualRelation (view_name ,view_tlist);
-
- /*
- * The relation we have just created is not visible
- * to any other commands running with the same transaction &
- * command id.
- * So, increment the command id counter (but do NOT pfree any
- * memory!!!!)
- */
- CommandCounterIncrement();
-
- /*
- * The range table of 'view_parse' does not contain entries
- * for the "CURRENT" and "NEW" relations.
- * So... add them!
- * NOTE: we make the update in place! After this call 'view_parse'
- * will never be what it used to be...
- */
- UpdateRangeTableOfViewParse(view_name, view_parse);
- DefineViewRules(view_name, view_parse);
- }
-
- /*------------------------------------------------------------------
- * RemoveView
- *
- * Remove a view given its name
- *------------------------------------------------------------------
- */
- void
- RemoveView(view_name)
- Name view_name;
- {
- NameData rname;
-
- /*
- * first remove all the "view" rules...
- * Currently we only have one!
- */
- makeRetrieveViewRuleName(&rname, view_name);
- RemoveRewriteRule(&rname);
- #ifdef TUPLE_VIEW
- prs2RemoveTupleRule(&rname);
- #endif TUPLE_VIEW
- /*
- * we don't really need that, but just in case...
- */
- CommandCounterIncrement();
-
- /*
- * now remove the relation.
- */
- RelationNameDestroyHeapRelation(view_name);
- }
-